<template>
  <!-- 进度条 -->
  <div v-if="isProgress" class="progress">
    <p :style="'width:' + percentage + '%'"></p>
  </div>
  <!-- 页眉 -->
  <div v-if="pageData.pageHeaderOption" class="page_header">
    <div v-if="pageData.pageHeaderOption.type === 'text'" :style="style">
      {{ pageData.pageHeaderOption.textContent }}
    </div>
    <template v-else>
      <Swipe :autoplay="3000" class="my-swipe" indicator-color="white">
        <SwipeItem
          v-for="(img, k) in pageData.pageHeaderOption.images"
          :key="k"
        >
          <img :src="img.url" alt="" />
        </SwipeItem>
      </Swipe>
    </template>
  </div>
  <!-- 标题和简介 -->
  <div class="enroll_top m15">
    <h2 class="f20 t-center">{{ pageData?.enrollConfig?.enrollName || "" }}</h2>
  </div>
  <!-- 问题区域 -->
  <div
    v-for="(enrollItem, index) in enrollList"
    :key="index"
    class="survey_item"
  >
    <!-- 移动端 -->
    <div v-if="isMobile">
      <van-form
        v-show="index === newPage"
        @failed="onFailed"
        @submit="onSubmit"
      >
        <van-cell-group class="v_form_group">
          <template
            v-for="(item, childIndex) in enrollItem"
            :key="item.enrollItemId"
          >
            <component
              :is="dom[item.itemType]"
              :item="item"
              @change="onChange($event)"
            ></component>
          </template>
        </van-cell-group>
        <!-- 按钮区域 -->
        <div class="fixed_btn">
          <div class="err_msg">
            <p v-for="(text, i) in subErrorMsg" :key="i" class="f12 red">
              {{ text }}
            </p>
          </div>
          <div class="btn_flex">
            <van-button
              v-if="enrollList.length > 1 && newPage !== 0"
              block
              class="mr15"
              plain
              type="primary"
              @click="newPage--"
            >上一页
            </van-button>
            <van-button block native-type="submit" type="primary">
              {{ index < enrollList.length - 1 ? "下一页" : "提交" }}
            </van-button>
          </div>
        </div>
      </van-form>
    </div>
    <!-- 电脑端 -->
    <div v-else>
      <ElForm
        v-if="index === newPage"
        ref="ruleFormRef"
        :model="enrollList[index]"
        label-position="top"
      >
        <template
          v-for="(item, childIndex) in enrollItem"
          :key="item.enrollItemId"
        >
          <component
            :is="domPc[item.itemType]"
            :childIndex="childIndex"
            :enrollItem="enrollItem"
            :index="index"
            :item="item"
            @change="onChange($event)"
          ></component>
        </template>
        <div class="m15 mb50 t-center">
          <ElButton
            v-if="enrollList.length > 1 && newPage !== 0"
            class="w100 mr15"
            plain
            type="primary"
            @click="newPage--"
          >
            上一页
          </ElButton>
          <ElButton class="w100" type="primary" @click="submitPc(ruleFormRef)">
            {{ index < enrollList.length - 1 ? "下一页" : "提交" }}
          </ElButton>
        </div>
      </ElForm>
    </div>
  </div>
  <!-- 不能填报的提示 -->
  <Popup
    v-model:show="showPopup"
    :close-on-click-overlay="false"
    :overlay-style="{ background: '#fff' }"
    round
  >
    <Empty :description="resMsg" class="empty" image-size="100" />
  </Popup>
  <!-- 提交动画遮罩 -->
  <Overlay :show="showOverlay">
    <div class="submit_loading">
      <Loading vertical>提交中...</Loading>
    </div>
  </Overlay>
  <!-- 底部弹出 -->
  <AuthPopup v-model="showBottom" @allow="allow()" @reject="router.back()" />
</template>

<script setup>
import AuthPopup from "@/components/AuthPopup/index.vue";
import COMPONENTS_H5 from "@/components/components-h5/index";
import COMPONENTS_PC from "@/components/components-pc/index";
import {
  apiCheckToken,
  getDetail,
  submitEnroll,
  updateUvEvery
} from "@/server/business/enroll.js";
import { uploadFile } from "@/server/common/file.js";
import { commonStore } from "@/stores/common.js";
import { enrollStore } from "@/stores/enroll.js";
import { setWeappToken } from "@/utils/auth.js";
import {
  formatDate,
  getDeviceInfo,
  getUrlQuery,
  getSource,
  wxPageRedirect
} from "@/utils/common.js";
import { handleLogicData, hideQuestionsWithoutOption } from "@/utils/logic.js";
import { ElButton, ElForm, ElMessage } from "element-plus";
import { storeToRefs } from "pinia";
import {
  closeToast,
  Empty,
  Loading,
  Overlay,
  Popup,
  showLoadingToast,
  Swipe,
  SwipeItem
} from "vant";
import { computed, inject, onMounted, reactive, ref } from "vue";
import { useRoute, useRouter } from "vue-router";

const useQuery = getUrlQuery(); // href获取数据
const store = commonStore();
const { isMobile } = storeToRefs(store);
const route = useRoute();
const router = useRouter();
const dom = COMPONENTS_H5; // 移动端的组件
const domPc = COMPONENTS_PC; // pc端的组件
const pageData = reactive({});
const newPage = ref(0); // 当前页码
const enrollList = ref([]); // 分页答题数据 修改此数据 实现页面联动
const enrollIndex = ref(0); // 处理数据的时候用来存放第几页
const showOverlay = ref(false);
const metaData = []; // 整理好的元数据
const clientData = {}; // 客户端数据
const subErrorMsg = ref([]); // 提交表单报错信息
const showPopup = ref(false); // 不能填报信息展示
const resMsg = ref(); // 不能填报原因
const ruleFormRef = ref(); // pc端表单
const percentage = ref(0); // 进度条 数值
const isProgress = ref(false); // 进度条 是否展示
const backTop = inject("backTop"); // 返回顶部
const showBottom = ref(false);
let memberInfo = {};
let metaInfo = {}
let hiddenQuestionData = []; // 隐藏问题的数据 只有工会组件有隐藏功能
const style = computed(() => {
  let { font } = pageData.pageHeaderOption;
  return {
    fontSize: font.size + "px",
    color: font.color,
    fontWeight: font.bold ? "bold" : "400",
    fontStyle: !font.italic ? "initial" : "italic",
    textDecoration: !font.underline ? "initial" : "underline",
    textAlign: font.align,
    background: font.background
  };
});

// 值发生变动
const onChange = (event) => {
  // 交互逻辑检测
  handleLogicData(metaData, pageData, event); // 逻辑处理
  handleRenderData(); // 数据从新渲染
  if (isProgress.value) {
    let newList = enrollList.value.flat(2);

    let already = 0;
    let total = newList.length;
    newList.forEach((item) => {
      if (item.value && item.value.length > 0) already++;
    });
    percentage.value = (already / total) * 100;
  }
};
// 提交 / 下一页
const onSubmit = () => {
  backTop();
  subErrorMsg.value = [];
  if (newPage.value === enrollList.value.length - 1) {
    handleSubmitData(); // 整理提交数据后在提交
  } else {
    newPage.value++;
  }
};
// pc 端提交
const submitPc = async (ruleForm) => {
  if (!ruleForm) return;
  ruleForm[0].validate((field) => {
    if (field) onSubmit();
  });
};
// 整理数据
const handleSubmitData = () => {
  let newList = enrollList.value.flat(2);
  newList = newList.concat(hiddenQuestionData);
  let pall = newList.map((item) => getEnrollItemVal(item));
  showOverlay.value = true;
  Promise.all(pall)
    .then((list) => {
      let pageHeader = {
        pageHeaderOption: pageData.pageHeaderOption,
        enrollName: pageData.enrollName
      };
      enrollStore().setEnrollInfo({
        pageData: { ...pageHeader, ...pageData },
        enrollList: enrollList.value
      }); // 先将数据缓存 需要先上传文件 然后将enrollList里面的文件数据替换成上传后的数据
      let params = {
        answerReqList: list,
        ...clientData,
        endTime: formatDate(new Date(), "yyyy-MM-dd hh:mm:ss"),
        userInfo: memberInfo,
        pageFullData: JSON.stringify({
          pageData: pageHeader,
          enrollList: enrollList.value
        })
      };
      if (useQuery.staffUserId) {
        params.staffUserId = useQuery.staffUserId;
      }
      submitEnroll(params)
        .then(({ msg }) => {
          ElMessage.success(msg || "提交成功");
          router.replace({ name: "EnrollSuccess" }); // 跳转到成功页面
        })
        .finally(() => {
          showOverlay.value = false;
        });
    })
    .catch((msg) => {
      console.error(msg);
    });
};
// 同步获取值
const getEnrollItemVal = (item = {}) => {
  return new Promise((resolve) => {
    let findFile = ["file-upload", "picture-upload"]; // 文件需要上传文件后 拿到上传文件成功后返回的地址
    if (findFile.includes(item.itemType)) {
      let fileData = customUploadFile(item); // 返回一个promise
      resolve(fileData);
    } else {
      let values = "";
      let ids = "";
      let respondData = JSON.parse(JSON.stringify(item.value || ""));
      if (item.itemType === "radio") {
        let obj2 = (item.itemOptResList || []).filter((rowObj) => {
          // 修改：上面代码空数组，row取值会报错
          const row = rowObj ? rowObj : {};
          return row.optionName === respondData;
        })[0];
        let obj = obj2 ? obj2 : {};
        values = obj ? obj.optionValue : "";
        ids = obj ? obj.itemOptionId : "";
        if (obj && obj.isOther === "Y") respondData = obj.otherValue;
      }
      if (item.itemType === "checkbox") {
        values = [];
        ids = [];
        (item.itemOptResList || []).forEach((rowObj) => {
          const row = rowObj || {};
          if (item.value.includes(row.optionName)) {
            values.push(row ? row.optionValue : "");
            ids.push(row ? row.itemOptionId : "");
          }
          let i = respondData.indexOf(row.optionName);
          if (i >= 0 && row.isOther === "Y") {
            respondData[i] = row.otherValue;
          }
        });
      }
      if (item.itemType === "select" || item.itemType === "tradeunion") {
        let obj = (item.itemOptResList || []).filter((rowObj) => {
          return rowObj.optionName === item.value;
        })[0];
        values = obj ? obj.optionValue : "";
        ids = obj ? obj.itemOptionId : "";
      }
      resolve({
        enrollItemId: item.enrollItemId,
        respondData: respondData ? respondData.toString() : "",
        respondValue: values ? values.toString() : "",
        respondId: ids ? ids.toString() : "",
        enrollItemType: item.itemType
      });
    }
  });
};
// 文件上传
const customUploadFile = (item) => {
  return new Promise((resolve) => {
    let pall = item.value.map((file) => {
      let formDate = new FormData();
      formDate.append("file", file.file || file.raw);
      return uploadFile(formDate);
    });
    Promise.all(pall)
      .then((list) => {
        item.value = list.map((next) => {
          return { ...next.data, file: { name: next.data.name } };
        }); // 偷偷 将value的file对象改成 接口返回的obj
        resolve({
          enrollItemId: item.enrollItemId,
          respondData: JSON.stringify(item.value || "")
        });
      })
      .catch((msg) => console.error(msg));
  });
};
// 提交报错信息
const onFailed = (errorInfo) => {
  if (pageData.enrollConfig.isOneItemPage === "Y") return;
  subErrorMsg.value = errorInfo.errors.map((item) => item.message);
};
// 获取问卷详情
const getEnrollDetail = () => {
  showLoadingToast({
    message: "加载中...",
    forbidClick: true,
    duration: 0
  });
  let params = { get_request: { enrollId: route.query.id } };
  getDetail(params).then(async ({ data }) => {
    closeToast();
    document.title = data?.enrollConfig.enrollName || "业务中台";
    // 暂停收集collectStatus===3
    if (
      data &&
      data.enrollConfig &&
      data.enrollConfig.collectStatus &&
      Number(data.enrollConfig.collectStatus) === 3
    ) {
      showPopup.value = true;
      resMsg.value = "当前报名已暂停收集";
      return;
    }
    // 报名收集时间limitDate
    if (
      data &&
      data.enrollConfig &&
      data.enrollConfig.limitDate &&
      data.enrollConfig.limitDate.length
    ) {
      if (
        new Date().getTime() -
        new Date(data.enrollConfig.limitDate[1]).getTime() >=
        0
      ) {
        // 已过收集时间
        showPopup.value = true;
        resMsg.value = "当前报名收集时间已结束";
        return;
      } else if (
        new Date().getTime() -
        new Date(data.enrollConfig.limitDate[0]).getTime() <=
        0
      ) {
        // 未到收集时间
        showPopup.value = true;
        resMsg.value = "当前时间不能参与报名";
        return;
      }
    }
    // 限制数量：limitNum为0的时候默认为无限制，collectNum收集数量、limitNum限制数量
    if (
      data &&
      data.enrollConfig &&
      data.enrollConfig.limitNum !== "0" &&
      Number(data.enrollConfig.collectNum) ===
      Number(data.enrollConfig.limitNum)
    ) {
      showPopup.value = true;
      resMsg.value = "当前报名收集数量已达上限";
      return;
    }
    resMsg.value = data.checkFillingEnable;
    showPopup.value = !!data.checkFillingEnable;
    if (showPopup.value) return; // 不能填报 直接展示错误信息 不去渲染页面
    Object.assign(pageData, data);
    if (!useQuery.staffUserId) {
      metaInfo = JSON.parse(data.metaInfo)
      await needCheckToken(data.enrollConfig.memberRange);
    } // 非面向所有人 需要校验
    dialogConfirm(data.enrollItemResList, data);
  });
};
// 弹出授权框
const dialogConfirm = (enrollItemResList, data) => {
  let has = (enrollItemResList || []).some((item) =>
    [
      "membername",
      "membermobile",
      "memberidentity",
      "tradeunion",
      "companyname"
    ].includes(item.itemType)
  );
  if (has) {
    showBottom.value = true;
  } else {
    handleMetaData(data.enrollItemResList || []);
    isProgress.value = JSON.parse(data.metaInfo)?.formConfig?.showProgress;
  }
};
// 同意
const allow = () => {
  showBottom.value = false;
  handleMetaData(pageData.enrollItemResList || []);
  isProgress.value = JSON.parse(pageData.metaInfo)?.formConfig?.showProgress;
};
// 小程序数据替换
const resetMiniAppToMeta = (item = {}) => {
  let itemTypeMap = new Map();
  itemTypeMap
    .set("membername", memberInfo.name || "")
    .set("membermobile", memberInfo.contactPhone || "")
    .set("memberidentity", memberInfo.idNum || "")
    .set("tradeunion", memberInfo.districtTradeUnionName || "")
    .set("companyname", memberInfo.companyName || "");
  item.value = itemTypeMap.get(item.itemType);
};
// 元数据 处理
const handleMetaData = (enrollItemResList = []) => {
  let types = ["checkbox", "picture-upload", "file-upload", "rate", "slider"];
  enrollItemResList.forEach((obj) => {
    const item = obj || {};
    const vformJson = JSON.parse(item.vformJson || "{}");
    if (item.itemType === "select") {
      let isMultiple = vformJson.options.isMultiple;
      if (isMultiple && isMobile) item.itemType = "checkbox"; // 下拉选择 开启多选且移动端的时候 直接将类型改成‘多选’
    }
    item.list = [];
    item.value = types.includes(item.itemType) ? [] : "";
    item.itemOptResList = (item.itemOptResList || []).map((itemOpt) => {
      itemOpt.otherValue = null;
      itemOpt.show = ref(true);
      return itemOpt;
    });
    if (["checkbox", "radio"].includes(item.itemType)) {
      let lists = [];
      (item.itemOptResList || []).forEach((next) => {
        if (next.isDefault === "Y") lists.push(next.optionName);
      });
      if (lists.length > 0)
        item.value = item.itemType === "radio" ? lists[0] : lists;
    } // 多选,单选 设置默认值
    item.hiddenQuestion = vformJson.options?.hiddenQuestion || false;
    item.orderNum = vformJson.ordNum; // 序号showOrderNum
    item.orderId = vformJson.id;
    item.show = true;
    resetMiniAppToMeta(item);
    metaData.push(item);
  });
  handleLogicData(metaData, pageData); // 逻辑处理
  handleRenderData();
};
// 一题一页数据处理
const oneQuestionOnePage = (item) => {
  if (item.hiddenQuestion) {
    hiddenQuestionData.push(item);
  } else if (
    !["slicer", "divider"].includes(item.itemType) &&
    !item.hiddenQuestion &&
    !hideQuestionsWithoutOption(item)
  ) {
    // 一页一题，去掉不显示的
    enrollList.value[enrollIndex.value] = [];
    enrollList.value[enrollIndex.value].push(item);
    enrollIndex.value++;
  }
};
// 默认处理（非一题一页）
const handleDefaultData = (item) => {
  if (item.itemType !== "slicer") {
    if (item.hiddenQuestion) {
      hiddenQuestionData.push(item);
    } else if (!hideQuestionsWithoutOption(item)) {
      if (!enrollList.value[enrollIndex.value]) {
        enrollList.value[enrollIndex.value] = [];
      }
      enrollList.value[enrollIndex.value].push(item);
    }
  } else {
    enrollIndex.value++;
  }
};
// 渲染页面的数据处理
const handleRenderData = () => {
  enrollIndex.value = 0;
  enrollList.value = [];
  hiddenQuestionData = [];
  metaData.forEach((item) => {
    if (eval(item.show)) {
      pageData?.enrollConfig?.isOneItemPage === "Y"
        ? oneQuestionOnePage(item)
        : handleDefaultData(item);
    }
  });
};
// 采集客户端数据
const getClientData = () => {
  getSource().then((type) => {
    clientData.source = type || "h5";
  });
  const deviceInfo = getDeviceInfo();
  clientData.browseType = deviceInfo.browseType;
  clientData.deviceType = deviceInfo.model;
  clientData.osVersion = deviceInfo.os;
  clientData.startTime = formatDate(new Date(), "yyyy-MM-dd hh:mm:ss");
  clientData.enrollId = route.query.id;
};
// 跳转微信登录
const goWxLogin = () => {
  wxPageRedirect(
    "../authLoginNew/authLoginNew?url=" +
    encodeURIComponent(location.href + "&token=#token#")
  );
};
// token验证
const checkToken = async (type) => {
  return new Promise((resolve, reject) => {
    if (useQuery.token && !["#token%23", "#token#"].includes(useQuery.token)) {
      setWeappToken(useQuery.token);
      apiCheckToken({ memberUserToken: useQuery.token })
        .then((res) => {
          memberInfo = res.data;
          if (
            pageData &&
            pageData.enrollConfig &&
            pageData.enrollConfig.enrollTo &&
            pageData.enrollConfig.enrollTo !== "all"
          ) {
            if (type === "register") {
              resolve(); // 注册用户
            } else if (type === "realName") {
              let isRealName = memberInfo.name && memberInfo.idNum;
              isRealName ? resolve() : reject("pseudonym"); // 实名职工
            } else if (type === "member") {
              let isMember =
                memberInfo.companyName && memberInfo.districtTradeUnionName;
              isMember ? resolve() : reject("joinUnion"); // 工会会员
            } else {
              reject("noType");
            }
          } else {
            resolve();
          }
        })
        .catch((msg) => {
          resolve("apiError", msg);
        });
    } else {
      // 判断是否小程序访问
      if (
        pageData &&
        pageData.enrollConfig &&
        pageData.enrollConfig.enrollTo &&
        pageData.enrollConfig.enrollTo !== "all"
      ) {
        // 非面向所有人 需要校验
        getSource().then((type) => {
          console.log("type=", type, "isDev=", import.meta.env.VITE_APP_ENV);
          if (type === "weapp") {
            reject("noToken"); // 没有token 小程序跳登录
          } else {
            if (["development"].includes(import.meta.env.VITE_APP_ENV)) {
              resolve(); // 开发环境 允许访问
            } else {
              reject("forbidden"); // 没有token 网页禁止访问
            }
          }
        });
      } else {
        resolve();
      }
    }
  });
};
// 错误时执行方法集合
const errorFun = {
  noToken: () => goWxLogin(),
  forbidden: () => {
    showPopup.value = true;
    resMsg.value = "请通过小程序访问";
  },
  pseudonym: () => {
    showPopup.value = true;
    resMsg.value = "此活动仅限“实名职工”参加，请先进行实名认证";
  },
  joinUnion: () => {
    showPopup.value = true;
    resMsg.value = "此活动仅限“工会会员”参加，请先入会";
  },
  noType: () => {
    showPopup.value = true;
    resMsg.value = "限制人群类型错误";
  }
};
// 校验合集
const checks = {
  // 仅注册用户
  register: () => {
    return checks.isTime(
      new Date(memberInfo.logonTime).getTime(),
      `仅限${metaInfo.enrollConfig.joinDateStart}~${metaInfo.enrollConfig.joinDateEnd}时间注册的用户可以提交问卷`
    );
  },
  //仅实名职工 realName
  realName: () => {
    return checks.isTime(
      new Date(memberInfo.realNameTime).getTime(),
      `仅限${metaInfo.enrollConfig.joinDateStart}~${metaInfo.enrollConfig.joinDateEnd}时间实名的用户可以提交问卷`
    );
  },
  //仅工会会员
  member: () => {
    return checks.isTime(
      new Date(memberInfo.membershipTime).getTime(),
      `仅限${metaInfo.enrollConfig.joinDateStart}~${metaInfo.enrollConfig.joinDateEnd}时间加入工会的会员可以提交问卷`
    )
  },
  // 时间限制条件
  isTime: (time, errMsg) => {
    let startTime = new Date(metaInfo.enrollConfig.joinDateStart).getTime();
    let endTime = new Date(metaInfo.enrollConfig.joinDateEnd).getTime();
    if (time < startTime || time > endTime) {
      return errMsg
    }else{
      return 
    }
  },
  // 错误提示
  errorMsg: (msg) => {
    showPopup.value = true;
    resMsg.value = msg
  }
}
// 需要token验证的情况
const needCheckToken = (type) => {
  return new Promise((resolve, reject) => {
    checkToken(type)
      .then(() => {
        if(metaInfo.enrollConfig.isJoinTime === 'Y'){
          let msg = checks[type]()
          msg ? checks.errorMsg(msg) : resolve();
        }else{
          resolve();
        }
      })
      .catch((msg) => {
        errorFun[msg](msg);
        reject();
      });
  });
};
// 挂载后运行
onMounted(() => {
  getEnrollDetail();
  getClientData(); // 获取系统
  updateUvEvery({ enrollId: route.query.id }); // 更新访问量
});
</script>
<style lang="less" scoped>
.page_header {
  margin-top: 3px;
}

.submit_loading {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
}

.survey_item :deep(.van-field__control--custom) {
  display: block;
}

.my-swipe :deep(.van-swipe-item) {
  color: #fff;
  height: 16rem;
  text-align: center;
  background-color: #39a9ed;

  img {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }
}

.fixed_btn {
  position: fixed;
  bottom: -1px;
  width: 34.5rem;
  padding: 1.5rem;
  background: #fff;
  border: none;
  box-shadow: 0 0 1rem var(--van-gray-3);

  .err_msg {
    max-height: 6rem;
    overflow-x: hidden;
    overflow-y: auto;
  }
}

.btn_flex {
  display: flex;
}

.v_form_group {
  padding-bottom: 14rem;
}

.progress {
  position: fixed;
  top: 0;
  width: 100%;
  left: 0;
  z-index: 9999;
  height: 3px;
  margin: 0;
  padding: 0;
  background: #fff;
}

.progress p {
  position: absolute;
  left: 0;
  top: 0;
  margin: 0;
  padding: 0;
  background: var(--el-color-primary);
  height: 3px;
}

.w100 {
  width: 180px;
  padding: 20px;
}

.empty {
  --van-empty-description-padding: 0 40px;
}
</style>
